'+longArr.join(''));
}
return msg;
},
tokenConfig = function(menu){
var linkQuery = '?{Name of attribute to link to, case insensitive. Repeating Sections not valid}';
return !menu ? '
'//markermsg div start
+'
Maintain PC Default Tokens:'+makeButton('!pfc --config,defaultToken='+(state.PFCompanion.defaultToken.enable==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.defaultToken.enable==='on' ? 'ON' : 'OFF'),(state.PFCompanion.defaultToken.enable==='on' ? 'green' : 'red'),'black','Keep non-mook character'+ch("'")+'s default tokens updated when anything but bar values changes.')+'
'
+'
Nameplate'+makeButton('!pfc --config,showname='+(state.PFCompanion.defaultToken.showname==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.defaultToken.showname==='on' ? '3':'_'),'transparent','black','Toggle nameplate')+'
'
+(state.PFCompanion.defaultToken.enable==='on' ?
'
'
+''
+''
+''
+''
+'| | '
+'Bar 3 | '
+'Bar 1 | '
+'Bar 2 | '
+'
'
+'| Link | '
+''+makeButton('!pfc --config,bar3Link='+linkQuery+' --config',(state.PFCompanion.defaultToken.bar3Link || '_'),'transparent',(state.PFCompanion.defaultToken.bar3Link ? 'black' : 'transparent'),'The name of the attribute that all tokens should either link this bar to(PCs and non-mook NPCs) or pull their starting values from (mooks)')+' | '
+''+makeButton('!pfc --config,bar1Link='+linkQuery+' --config',(state.PFCompanion.defaultToken.bar1Link || '_'),'transparent',(state.PFCompanion.defaultToken.bar1Link ? 'black' : 'transparent'),'The name of the attribute that all tokens should either link this bar to(PCs and non-mook NPCs) or pull their starting values from (mooks)')+' | '
+''+makeButton('!pfc --config,bar2Link='+linkQuery+' --config',(state.PFCompanion.defaultToken.bar2Link || '_'),'transparent',(state.PFCompanion.defaultToken.bar2Link ? 'black' : 'transparent'),'The name of the attribute that all tokens should either link this bar to(PCs and non-mook NPCs) or pull their starting values from (mooks)')+' | '
+'
'
+'| Visible | '
+''+makeButton('!pfc --config,bar3Visible='+(state.PFCompanion.defaultToken.bar3Visible==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.defaultToken.bar3Visible==='on' ? '3' : '_'),'transparent','black','Is this bar visible to players by default or not')+' | '
+''+makeButton('!pfc --config,bar1Visible='+(state.PFCompanion.defaultToken.bar1Visible==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.defaultToken.bar1Visible==='on' ? '3' : '_'),'transparent','black','Is this bar visible to players by default or not')+' | '
+''+makeButton('!pfc --config,bar2Visible='+(state.PFCompanion.defaultToken.bar2Visible==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.defaultToken.bar2Visible==='on' ? '3' : '_'),'transparent','black','Is this bar visible to players by default or not')+' | '
+'
'
+'
'
+makeButton('!pfc --token,defaults,folder=?{Apply to which Folder}','Apply to Folder','transparent','black','Apply the above token defaults to all characters with a token on the VTT in a specific folder')+'
'+makeButton('!pfc --token,defaults','Apply to All','transparent','black','Apply the above token defaults to all characters with a token on the VTT')+''
:
'')
+'
' : '';
},
affectConfig = function(menu){
return !menu ? '
'
+'
Damage/Effect Listener:'+makeButton('!pfc --config,status='+(state.PFCompanion.affect.status==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.status==='on' ? 'ON' : 'OFF'),(state.PFCompanion.affect.status==='on' ? 'green' : 'red'),'black','Toggle listening for damage and effects of weapons, spells, and abilities.')+'
'
+(state.PFCompanion.affect.status==='on' ?
'
'
+''
+''
+''
+''
+'| | '
+'Apply Effects | '
+'Roll Saves | '
+'
'
+'| PCs | '
+''+makeButton('!pfc --config,pcaffect='+(state.PFCompanion.affect.pcaffect==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.pcaffect==='on' ? '3' : '_'),'transparent','black','Automatically determine effects on PCs')+' | '
+''+makeButton('!pfc --config,pcroll='+(state.PFCompanion.affect.pcroll==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.pcroll==='on' ? '3' : '_'),(state.PFCompanion.affect.pcaffect==='on' ? 'transparent' : '#D3D3D3'),'black','Automatically roll saves for PCs')+' | '
+'
'
+'| Mooks | '
+''+makeButton('!pfc --config,mookaffect='+(state.PFCompanion.affect.mookaffect==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.mookaffect==='on' ? '3' : '_'),'transparent','black','Automatically determine effects on mooks')+' | '
+''+makeButton('!pfc --config,mookroll='+(state.PFCompanion.affect.mookroll==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.mookroll==='on' ? '3' : '_'),(state.PFCompanion.affect.mookaffect==='on' ? 'transparent' : '#D3D3D3'),'black','Automatically roll saves for mooks')+' | '
+'
'
+'| Named NPCs | '
+''+makeButton('!pfc --config,npcaffect='+(state.PFCompanion.affect.npcaffect==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.npcaffect==='on' ? '3' : '_'),'transparent','black','Automatically determine effects on npcs')+' | '
+''+makeButton('!pfc --config,npcroll='+(state.PFCompanion.affect.npcroll==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.affect.npcroll==='on' ? '3' : '_'),(state.PFCompanion.affect.npcaffect==='on' ? 'transparent' : '#D3D3D3'),'black','Automatically roll saves for npcs')+' | '
+'
'
+'
' : '')
:''
},
mookConfig = function(menu){
return !menu ? '
'//markermsg div start
+'
Mook Numbering:'+makeButton('!pfc --config,mook='+(state.PFCompanion.mook==='on' ? 'off' : 'on')+' --config',(state.PFCompanion.mook==='on' ? 'ON' : 'OFF'),(state.PFCompanion.mook==='on' ? 'green' : 'red'),'black','Number mook tokens as they are placed on the VTT.')+'
' : '';
},
configAssembler = function(who,menu){
var msg = '/w "'+who+'"
'//overall div for nice formatting of control panel
+'
'//Control Panel Header div
+'[Pathfinder]('+mediumLogo+')
Companion API Script v'+version+' Options'
+'
'+tokenSetupConfig(menu)+resourceConfig(menu)+hpConfig(menu)+mookConfig(menu)+tokenConfig(menu)+markerConfig(who,menu)+affectConfig(menu)
+'
'
+makeButton('!pfc --i','APPLY SETTINGS TO CAMPAIGN','#C0C0C0','#228B22','Reinitialize the campaign, this may take several minutes depending on campaign size.')+'
';//end Control Panel Header div
sendChat('Pathfinder Companion',msg,null,{noarchive:true});
},
configHandler = function(who,details){
try{
var detailKeys = _.keys(details),
validKeys = [,'hp','ResourceTrack','TAS','mook'],
createKeys = [/skill$/,/skillc$/,/checks$/,/defense$/,/attack$/,/abilities$/,/item$/,/initiative$/,/spellbook$/,/fort$/,/will$/,/ref$/,/allmenus$/],
markerKeys = ['markers','Bleed','Blinded','Cowering','Dazed','Dazzled','Dead','Deafened','Disabled','Drowning','Dying','Energy Drain','Entangled','Exhausted','Fascinated','Fatigued','Fear','Flat-Footed','Grappled','Helpless','Incorporeal','Invisible','Nauseated','Paralyzed','Petrified','Pinned','Prone','Sickened','Stable','Staggered','Stunned','Suffocating','Unconscious'],
tokenKeys = ['defaultToken','bar1Link','bar1Visible','bar2Link','bar2Visible','bar3Link','bar3Visible','showname'],
affectKeys = ['status','mookaffect','npcaffect','pcaffect','mookroll','npcroll','pcroll'],
npc,allKeys;
allKeys = validKeys.concat(markerKeys,createKeys,tokenKeys,affectKeys);
if(!_.some(allKeys,(ak)=>{return _.some(detailKeys,(dk)=>{return (dk.match(ak))})}) || _.indexOf(detailKeys,'menu')>-1){
configAssembler(who,details.menu);
return;
}
_.each(detailKeys,(dk)=>{
_.some(validKeys,(vk)=>{return vk===dk}) ? state.PFCompanion[dk]=details[dk] : undefined;
_.some(createKeys,(ck)=>{
if(dk.match(ck)){
dk.match(/^npc/) ? state.PFCompanion.npcToCreate[dk.replace('npc','')] = details[dk] : state.PFCompanion.toCreate[dk] = details[dk];
return true;
}else{return false}
});
_.some(markerKeys,(mk)=>{
if(dk===mk){
state.PFCompanion.markers[mk]=details[mk];
return true;
}else{return false}
});
_.some(affectKeys,(ak)=>{
if(dk===ak){
if(ak.match(/roll/)){
state.PFCompanion.affect[ak]=state.PFCompanion.affect[ak.replace('roll','affect')]==='on' ? details[ak] : 'off';
}else if(ak.match(/affect/)){
state.PFCompanion.affect[ak]=details[ak];
if(details[ak]==='off'){
state.PFCompanion.affect[ak.replace('affect','roll')]='off';
}
}else{
state.PFCompanion.affect[ak]=details[ak];
}
return true;
}else{return false}
});
_.some(tokenKeys,(tk)=>{
if(dk.match(tk)){
dk==='defaultToken' ? state.PFCompanion.defaultToken.enable=details[tk] : (tk===dk ? state.PFCompanion.defaultToken[tk]=details[tk] : state.PFCompanion.defaultToken[tk]=undefined);
}
});
});
}catch(err){
sendError(err);
}
},
extractRoll = function(msg){
return _.chain(msg.inlinerolls)
.reduce(function(m,v,k){
m['$[['+k+']]']=v.results.total || 0;
return m;
},{})
.reduce(function(m,v,k){
return m.replace(k,v);
},msg.content)
.value();
},
HandleInput = async function(msg_orig) {
if(!sheetCompat){
if(msg_orig.content==='!pfcoverridecompatibility'){
sheetCompat=true;
sendChat('Pathfinder Companion','/w gm Compatibility check overridden. Please note that functionality is not guaranteed in this state and there may be unintended effects on sheets or the game as a whole.')
checkInstall();
}
return;
}
try{
var msg = _.clone(msg_orig),
who = idToDisplayName(msg.playerid),
args,cmdDetails,characters,folders;
if(msg.type !== 'api'){
if(msg.rolltemplate){
if(msg.rolltemplate.indexOf('pf')===0){
if(_.has(msg,'inlinerolls')){//calculates inline rolls
msg.content = extractRoll(msg);
}
listener(msg,who);
}
}
return;
}else if(msg.content.indexOf('!pfc')!==0){
return
}
if(_.has(msg,'inlinerolls')){//calculates inline rolls
msg.content = extractRoll(msg);
}
args = msg.content.split(/(?: )+--/);//splits the message contents into discrete arguments
args.shift();
let argWorker = async ()=>{
let a = args.shift();
cmdDetails = cmdExtract(a);
_.each(cmdDetails.details,(cd)=>{cd= cd==='' ? undefined : cd});
if(cmdDetails.things.length>0){
characters = _.chain(cmdDetails.things)
.map((t)=>{return getObj('character',t.trim())})
.reject((c)=>{return _.isUndefined(c)})
.value();
}else if(msg.selected){
characters = _.chain(msg.selected)
.map((s)=>{return getObj('graphic',s._id)})
.reject((c)=>{return _.isUndefined(c)})
.map((t)=>{return getObj('character',t.get('represents'))})
.reject((ch)=>{return _.isUndefined(ch)})
.value();
}
characters = !_.isEmpty(characters) ? characters : undefined;
switch(cmdDetails.action){
case 'help':
showHelp(who);
break;
case 'i':
if(playerIsGM(msg.playerid)){
sendChat('Pathfinder Companion','/w "'+who+'" All settings being applied to campaign',null,{noarchive:true});
initialize(who);
}
break;
case 'config':
if(playerIsGM(msg.playerid)){
configHandler(who,cmdDetails.details);
}
break;
case 'statuscontrol':
if(playerIsGM(msg.playerid) || characters[0].get('controlledby').match(msg.playerid)){
_.defer(statusControl,characters[0],who);
}
break;
case 'token':
var token,control,folders;
if(cmdDetails.details.defaults && playerIsGM(msg.playerid)){
if(cmdDetails.details.folder){
characters = [];
folders = Campaign().get('journalfolder').length>0 ? JSON.parse(Campaign().get('journalfolder')) : '';
if(folders.length>0){
_.some(folders,(f)=>{
if(f.n===cmdDetails.details.folder){
_.each(f.i,(i)=>{
characters.push(getObj('character',i));
});
}
});
characters = _.reject(characters,(c)=>{return _.isUndefined(c)});
}
}else{
characters = findObjs({type:'character'});
}
sendChat('Pathfinder Companion','/w gm Applying default token settings to indicated characters');
await new Promise((resolve,reject)=>{
_.defer((chars)=>{
_.each(chars,(c)=>{
mapBars(null,c);
});
resolve('done');
},characters);
});
sendChat('Pathfinder Companion','/w gm Default token settings applied');
}else{
if(!playerIsGM(msg.playerid)){
_.some(msg.selected,(s)=>{
token = getObj('graphic',s._id);
if(token){
control = _.isEmpty(token.get('represents')) ? token.get('controlledby') : getObj('character',token.get('represents')).get('controlledby');
if(control.match(msg.playerid)){
return true;
}else{
token = undefined;
return false;
}
}
});
}else{
_.some(msg.selected,(s)=>{
token = getObj('graphic',s._id);
if(token){
return true;
}else{
return false;
}
});
}
if(token){
tokenHandler(who,token,cmdDetails.details);
}
}
break;
//!pfc --resource[,item=AMMONAME][,spelllevel/spellname=#/SPELLNAME][,ability=ABILITYNAME][,current=X/+/-X][,max=X/+/-X]|Character id|character id|...
case 'resource':
if(characters && (cmdDetails.details.current || cmdDetails.details.max)){
if(cmdDetails.details.misc){
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
handleNoteCommand(cmdDetails.details.misc,c,cmdDetails.details.current,cmdDetails.details.max);
}
});
}
if(cmdDetails.details.item){
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
handleAmmoCommand(cmdDetails.details.item,c,cmdDetails.details.current,cmdDetails.details.max);
}
});
}
if(cmdDetails.details.spell){
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
handleSpellCommand(cmdDetails.details.spell,c,cmdDetails.details.class,cmdDetails.details.current,cmdDetails.details.silent);
}
});
}
if(cmdDetails.details.ability){
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
handleAbilityCommand(cmdDetails.details.ability,c,cmdDetails.details.class,cmdDetails.details.current,cmdDetails.details.max);
}
});
}
}
break;
case 'grouproll':
var tokens;
if(cmdDetails.details.roll && playerIsGM(msg.playerid)){
if(cmdDetails.details.roll.match(/init/i)){
if(cmdDetails.details.clear){
Campaign().set({turnorder:'',initiativepage:false});
}
tokens = _.chain(msg.selected)
.map((s)=>{
return getObj('graphic',s._id);
})
.reject((s)=>{return _.isUndefined(s)})
.reject((s)=>{return _.isEmpty(s.get('represents'))})
.value();
tokens = _.isEmpty(tokens) ? undefined : tokens;
}
if((cmdDetails.details.roll.match(/init/i) ? !_.isEmpty(tokens) : !_.isEmpty(characters))){
sendGroupRoll(tokens || characters,cmdDetails.details.roll,cmdDetails.details.whisper,cmdDetails.details.sort);
}
}
break;
case 'parse':
if(!playerIsGM(msg.playerid)){
return;
}
var chatText=[],
charText=[];
_.each(cmdDetails.things,(t)=>{
if(t.match(/^{{/)&&t.match(/}}$/)){
chatText.push(t.replace(/^{{|}}$/g,''));
}
});
if(characters){
if(msg.selected){
characters = _.reject(characters,(c)=>{return _.some(msg.selected,(s)=>{return getObj('graphic',s._id).get('represents') === c.id})});
}
_.each(characters,(c)=>{
charText.push(new Promise((resolve,reject)=>{
c.get('gmnotes',(n)=>{
if(n){
if(n!=='null'){
resolve(n);
}else{
resolve('no statblock');
}
}else{
resolve('no statblock');
}
});
}));
});
Promise.all(charText).then((t)=>{
t=_.reject(t,(arr)=>{return arr==='no statblock'});
_.each(t,(arr)=>{chatText.push(arr)});
statblockHandler(chatText.join('\nNEW CREATURE\n'),characters,who);
});
}else{
statblockHandler(chatText.join('\nNEW CREATURE\n'),null,who);
}
break;
case 'buffstatus':
if(characters){
if(playerIsGM(msg.playerid) || characters[0].get('controlledby').match(/all/i) || characters[0].get('controlledby').match(msg.playerid)){
buffSetup(characters[0],cmdDetails.details.buff,cmdDetails.details.markers,who);
}
}
break;
case 'apply':
if(characters && (cmdDetails.details.condition || cmdDetails.details.buff)){
var defaultTokens = [],
mooks = [];
tokens = [];
_.each(_.range(characters.length),(r)=>{
mooks.push(new Promise((resolve,reject)=>{
characters[r].get('_defaulttoken',(t)=>{
if(!_.isEmpty(t)){
let tok = JSON.parse(t);
if(_.every([1,2,3],(n)=>{return _.isEmpty(tok['bar'+n+'_link'])})){
resolve(tok.represents);
}else{
resolve(null);
}
}else{
resolve(null);
}
});
}));
});
mooks = await Promise.all(mooks);
mooks = _.chain(mooks)
.reject((m)=>{return _.isUndefined(m)})
.uniq()
.value();
tokens = _.chain(msg.selected)
.map((s)=>{return getObj('graphic',s._id)})
.reject((s)=>{return (_.isUndefined(s) || !_.some(mooks,(m)=>{return m===s.get('represents')}))})
.value();
characters = _.reject(characters,(c)=>{
return _.some(mooks,(m)=>{return m===c.id});
});
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
applyConditions(c,cmdDetails.details.condition,cmdDetails.details.buff,cmdDetails.details.swap,cmdDetails.details.remove,cmdDetails.details.rounds);
}
});
_.each(tokens,(t)=>{
applyConditions(t,cmdDetails.details.condition,cmdDetails.details.buff,cmdDetails.details.swap,cmdDetails.details.remove,cmdDetails.details.rounds);
})
}else{
//handling for improper command
}
break;
case 'whisper':
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
setWhisperState(c,cmdDetails.details.pc,cmdDetails.details.npc,cmdDetails.details.stats);
}
});
break;
case 'rest':
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid)||c.get('controlledby').match(msg.playerid)){
rest(c);
}
});
break;
case 'spellbook':
if(cmdDetails.details.class && !_.isEmpty(characters)){
if(cmdDetails.details.worker){
onSheetWorkerCompleted(()=>{msgSpellBook(characters[0],[cmdDetails.details.class])});
}else{
msgSpellBook(characters[0],[cmdDetails.details.class]);
}
}
break;
case 'TAS':
if(characters){
if(characters.length!==cmdDetails.things.length){
if(_.some(cmdDetails.things,(t)=>{return t==='ALL'})){
characters = findObjs({type:'character'});
}else{
folders = Campaign().get('journalfolder').length>0 ? JSON.parse(Campaign().get('journalfolder')) : '';
if(folders.length>0){
_.each(cmdDetails.things,(t)=>{
_.some(folders,(f)=>{
if(f.n===t){
_.each(f.i,(i)=>{
characters.push(getObj('character',i));
});
}
});
});
characters = _.reject(characters,(c)=>{return _.isUndefined(c)});
}
}
}
}else{
if(_.some(cmdDetails.things,(t)=>{return t==='ALL'})){
characters = findObjs({type:'character'});
}else{
folders = Campaign().get('journalfolder').length>0 ? JSON.parse(Campaign().get('journalfolder')) : '';
if(folders.length>0){
characters=[];
_.each(cmdDetails.things,(t)=>{
_.some(folders,(f)=>{
if(f.n===t){
_.each(f.i,(i)=>{
characters.push(getObj('character',i));
});
}
});
});
characters = _.reject(characters,(c)=>{return _.isUndefined(c)});
}
}
}
if(characters){
_.each(characters,(c)=>{
if(playerIsGM(msg.playerid) || c.get('controlledby').match(/all/i) || c.get('controlledby').match(msg.playerid)){
tokenActionMaker(c,cmdDetails.details.limit,cmdDetails.details.ignore,cmdDetails.details.remove);
}
});
}else{
showHelp(who);
}
break;
}
if(!_.isEmpty(args)){
argWorker();
}
};
if(!_.isEmpty(args)){
argWorker();
}else{
showHelp(who);
}
}catch(err){
sendError(err);
}
},
cmdExtract = function(cmd){
var cmdSep = {
details:{}
},
vars,details;
cmdSep.things = cmd.split('|');
details = cmdSep.things.shift();
cmdSep.things=_.map(cmdSep.things,(t)=>{
return t.trim();
});
details = details.split(',');
cmdSep.action = details.shift();
_.each(details,(d)=>{
vars=d.match(/(.*?)(?:\:|=)(.*)/) || null;
if(vars){
cmdSep.details[vars[1]]= (vars[1]==='limit'||vars[1]==='ignore') ? vars[2].split(/\s+/) : vars[2];
}else{
cmdSep.details[d]=d;
}
});
return cmdSep;
},
extractRowID = function(name){
return name.match(/(?:_(-[^_]+)_)/) ? name.match(/(?:_(-[^_]+)_)/)[1] : undefined;
},
characterHandler = function(obj,event,prev){
try{
if(!sheetCompat){
return;
}
var npcAbilities = ['NPC-spellbook-2','NPC-spellbook-1','NPC-spellbook-0','NPC-ability_checks','NPC-initiative_Roll','NPC-defenses','NPC-attacks','NPC-abilities','NPC-combat_skills','NPC-skills','NPC-items'],
pcAbilities = ['spellbook-2','spellbook-1','spellbook-0','ability_checks','Roll-for-initiative','defenses','attacks','abilities','combat_skills','skills','items'];
switch(event){
case 'add':
(state.PFCompanion.ResourceTrack==='on' || state.PFCompanion.TAS === 'auto') ? _.defer(initializeCharacter,obj) : undefined;
break;
case 'change':
if(state.PFCompanion.TAS==='auto' && obj.get('name')!==prev.name){
_.each(findObjs({type:'ability',characterid:obj.id}),(a)=>{
if(_.some(npcAbilities,(n)=>{return a.get('description')===n})){
a.remove();
}
if(_.some(pcAbilities,(n)=>{return a.get('description')===n})){
a.remove();
}
});
tokenActionMaker(obj);
}
break;
}
}catch(err){
sendError(err);
}
},
attributeHandler = async function(obj,event,prev){
try{
if(!sheetCompat){
return;
}
var defaultToken,barLinked;
switch(event){
case 'change':
if(obj.get('name')==='is_npc'){
if(obj.get('current')!==prev.current){
if(state.PFCompanion.TAS === 'auto'){
tokenActionMaker(getObj('character',obj.get('characterid')));
}
if(state.PFCompanion.ResourceTrack==='on'){
initializeCharacter(getObj('character',obj.get('characterid')));
}
}
}else if(obj.get('name').match('_ammo')){
if(state.PFCompanion.ResourceTrack==='on' && parseInt(obj.get('current'))!==0 && parseInt(prev.current)===0){
initializeRepeatingResourceTracking(extractRowID(obj.get('name')),findObjs({type:'attribute',characterid:obj.get('characterid')}));
}else if(state.PFCompanion.ResourceTrack!=='on' || parseInt(obj.get('current'))===0 && parseInt(obj.prev)!==0){
deleteAmmoTracking(extractRowID(obj.get('name')),findObjs({type:'attribute',characterid:obj.get('characterid')}));
}
}else if(obj.get('name').match(/spellclass-[012]-casting_type|repeating_ability_-.+_name|repeating_spells_-.+_name|repeating_ability_-.+_hasuses|repeating_item_-.+_name/)){
_.defer(initializeCharacter,getObj('character',obj.get('characterid')));
}else if(state.PFCompanion.ResourceTrack==='on' && obj.get('name').match(/_-.+_description|_-.+_notes/) && !obj.get('name').match(/buff/)){
_.defer(checkForCustomTracking,obj);
}else if(obj.get('name').toLowerCase()==='hp' && parseInt(obj.get('current'))!==parseInt(prev.current) && state.PFCompanion.hp==='on'){
_.defer(handleHP,obj,prev);
}else if(obj.get('name').match(/condition-.*|repeating_buff2_-[^_]+_enable_toggle/)){
let condName = obj.get('name').replace('condition-','');
let cbName = obj.get('name').match(/condition-.*/) ? state.PFCompanion.markers[(obj.get('name').replace('condition-','')==='Drained' ? 'Energy Drain' : obj.get('name').replace('condition-',''))] : getAttrByName(obj.get('characterid'),obj.get('name').replace('enable_toggle','name'));
let character = getObj('character',obj.get('characterid'));
if(!cbName){return}
defaultToken = await new Promise((resolve,reject)=>{
character.get('_defaulttoken',(t)=>{
if(!_.isEmpty(t)){
resolve(JSON.parse(t));
}else{
resolve(undefined);
}
});
});
barLinked = _.some([1,2,3],(b)=>{
return !_.isEmpty(defaultToken['bar'+b+'_link']);
});
if(barLinked){
cbName = cbName.replace(/(?:.*(?=\s+\|\|\s+))\s+\|\|\s+/,'');
if(cbName = statusquery[_.indexOf(statusquery,cbName)]){
applyStatus(character,cbName,parseInt(obj.get('current'))===0 ? false : (condName === 'Drained' ? Math.abs(parseInt(obj.get('current'))) : ((condName==='Fatigued' && parseInt(obj.get('current'))===3) ? '2' : true)));
}
}
}
break;
case 'add':
if(obj.get('name').match(/repeating_[^_]+_-[^_]+_name|repeating_[^_]+_-[^_]+_spell_level|repeating_[^_]+_-[^_]+_spellclass_number|repeating_[^_]+_-[^_]+_source-.+|repeating_[^_]+_-[^_]+_ammo/)){
setTimeout(()=>{
initializeRepeatingResourceTracking(extractRowID(obj.get('name')),findObjs({type:'attribute',characterid:obj.get('characterid')}));
},0);
}else if(obj.get('name').match(/_-.+_description$|_-.+_notes$/) && !obj.get('name').match(/buff/)){
_.defer(checkForCustomTracking,obj);
}else if(obj.get('name').match(/condition-.*|repeating_buff2_[^_]+_enable_toggle/)){
let cbName = obj.get('name').match(/condition-.*/) ? obj.get('name').replace('condition-','') : getAttrByName(obj.get('characterid'),obj.get('name').replace('enable_toggle','name'));
let character = getObj('character',obj.get('characterid'));
if(!cbName){return}
defaultToken = await new Promise((resolve,reject)=>{
character.get('_defaulttoken',(t)=>{
if(!_.isEmpty(t)){
resolve(JSON.parse(t));
}else{
resolve(undefined);
}
});
});
if(defaultToken){
barLinked = _.some([1,2,3],(b)=>{
return !_.isEmpty(defaultToken['bar'+b+'_link']);
});
}
if(barLinked){
cbName = cbName.replace(/(?:.*(?=\s+\|\|\s+))\s+\|\|\s+/,'');
_.some(statusquery,(sq)=>{return sq.match(cbName) ? cbName=sq : false});
applyStatus(character,cbName,parseInt(obj.get('current'))===0 ? false : true);
}
}
break;
case 'destroy':
break;
}
}catch(err){
sendError(err);
}
},
campaignHandler = async function(obj,event,prev,depth){
try{
var oTurn=obj.get('turnorder'),
pTurn=prev.turnorder,
conditionMatch = /Condition: (.*)/,
buffMatch = /Buff: (.*)/,
nameMatch = /(.*(?= (?:Condition:|Buff:))) (?:Condition:|Buff:) /,
newPrev=JSON.stringify(obj),
buff,condition,character,name,removed,defaultToken,barLinked,graphic;
depth = depth || 0;
if(oTurn!==pTurn && Campaign().get('initiativepage') && !_.isEmpty(oTurn)){
oTurn = JSON.parse(oTurn);
pTurn = !_.isEmpty(pTurn) ? JSON.parse(pTurn) : undefined;
if(_.isEmpty(oTurn)){
removed = pTurn;
if(!removed){
return;
}
}
removed = !_.isEmpty(pTurn) ? _.reject(pTurn,(p)=>{
return _.some(oTurn,(o)=>{
return p.custom===o.custom;
});
}) : undefined;
removed = _.isEmpty(removed) ? undefined : removed;
if(removed){
for(var i=0;i
{
character.get('_defaulttoken',(t)=>{
if(!_.isEmpty(t)){
resolve(JSON.parse(t));
}else{
resolve(undefined);
}
});
});
barLinked = _.some([1,2,3],(b)=>{
return !_.isEmpty(defaultToken['bar'+b+'_link']);
});
if(barLinked||graphic){
await applyConditions(graphic||character,condition,buff,undefined,'remove');
}
}
}
}else{
buff = oTurn[0].custom.match(buffMatch) ? oTurn[0].custom.match(buffMatch)[1] : undefined;
condition = oTurn[0].custom.match(conditionMatch) ? oTurn[0].custom.match(conditionMatch)[1] : undefined;
name = oTurn[0].custom.match(nameMatch) ? oTurn[0].custom.match(nameMatch)[1] : undefined;
character = name ? _.find(findObjs({type:'character',name:name})) : undefined;
if(!_.isEmpty(oTurn[0].token)){
graphic=getObj('graphic',oTurn[0].token);
}
if(depth===0){
log('oTurn: '+JSON.stringify(oTurn));
log('character: '+JSON.stringify(character));
log('graphic: '+JSON.stringify(graphic));
log('buff: '+buff);
log('condition: '+condition);
}
if((buff || condition) && oTurn[0].pr*1<=depth && (character || graphic)){
if(character){
defaultToken = await new Promise((resolve,reject)=>{
character.get('_defaulttoken',(t)=>{
if(!_.isEmpty(t)){
resolve(JSON.parse(t));
}else{
resolve(undefined);
}
});
});
barLinked = _.some([1,2,3],(b)=>{
return !_.isEmpty(defaultToken['bar'+b+'_link']);
});
}
if(barLinked||graphic){
await applyConditions(graphic||character,condition,buff,undefined,'remove');
campaignHandler(obj,'change',newPrev,1);
}
}
}
}
}catch(err){
sendError(err);
}
},
mookHandler = function(token,event){
var index,character;
switch(event){
case 'add':
tIDs.push(token.id);
break;
case 'change':
if((index =_.indexOf(tIDs,token.id))>-1){
if(_.every([1,2,3],(n)=>{return _.isEmpty(token.get('bar'+n+'_link'))})){
character = getObj('character',token.get('represents'));
if(character){
var tokenNames = _.chain(findObjs({type:'graphic',represents:character.id,pageid:token.get('pageid')}))
.reject((t)=>{return t.id===token.id})
.map((t)=>{return t.get('name').replace(character.get('name')+' ','')*1 || 0})
.reject((t)=>{return _.isNull(t)})
.value(),
number;
number = _.isEmpty(tokenNames) ? 1 : _.max(tokenNames)+ 1;
token.set('name',character.get('name')+' '+number);
}
}
tIDs.splice(index,1);
}
break;
}
},
graphicHandler = function(obj,event,prev){
try{
var character,added,removed,buffMatch,conditionKeys,
buffMarkers=[],
conditionMarkers=[],
updated=false,
ignoreChange=[1,2,3],
barLinked;
if(state.PFCompanion.mook==='on'){
mookHandler(obj,event);
}
if(event==='change'){
if(!_.isEmpty(obj.get('represents')) && obj.get('left')===prev.left && obj.get('top')===prev.top){
if(obj.get('represents')!==prev.represents){
mapBars(obj,getObj('character',obj.get('represents')));
}else if(!_.some(ignoreChange,(i)=>{return (obj.get('bar'+i+'_value')!==prev['bar'+i+'_value'] || obj.get('bar'+i+'_max')!==prev['bar'+i+'_max'])})){
character = getObj('character',obj.get('represents'));
if(character){
barLinked = _.some(ignoreChange,(b)=>{
return !_.isEmpty(obj.get('bar'+b+'_link'));
});
if(barLinked){
if(obj.get('statusmarkers')!==prev.statusmarkers){
removed = !_.isEmpty(prev.statusmarkers) ? _.reject(prev.statusmarkers.split(','),(p)=>{
return _.some(obj.get('statusmarkers').split(','),(o)=>{
return o===p;
});
}) : undefined;
added = !_.isEmpty(obj.get('statusmarkers')) ? _.reject(obj.get('statusmarkers').split(','),(p)=>{
return _.some(prev.statusmarkers.split(','),(o)=>{
return o===p;
});
}) : undefined;
_.each(findObjs({type:'attribute',characterid:character.id}),(a)=>{
if(a.get('name').match(/repeating_buff2_-[^_]+_name/)){
buffMatch = a.get('current').match(/(.*(?=\s+\|\|))\s+\|\|\s+(.*)/);
if(buffMatch){
buffMarkers.push({'name':buffMatch[1],'marker':buffMatch[2]});
}
}
});
conditionKeys = _.keys(state.PFCompanion.markers);
_.each(conditionKeys,(ck)=>{
conditionMarkers.push({'name':ck,'marker':state.PFCompanion.markers[ck]});
});
_.each(removed,(r)=>{
_.each(conditionMarkers,(c)=>{
if(r.match(c.marker)){
updated=true;
if(r.match(/@2/) && c.name==='Fatigued'){
c.name='Exhausted';
}else if(r.match(/@\d/) && c.name==='Energy Drain'){
c.name='Energy Drain '+r.match(/@(\d)/)[1];
}
applyConditions(character,c.name,null,null,'remove');
}
});
_.each(buffMarkers,(b)=>{
if(r.match(b.marker)){
updated=true;
applyConditions(character,null,b.name,null,'remove');
}
});
});
_.each(added,(a)=>{
_.each(conditionMarkers,(c)=>{
if(a.match(c.marker)){
updated=true;
if(a.match(/@2/) && c.name==='Fatigued'){
c.name='Exhausted';
}else if(a.match(/@\d/) && c.name==='Energy Drain'){
c.name='Energy Drain '+a.match(/@(\d)/)[1];
}
applyConditions(character,c.name);
}
});
_.each(buffMarkers,(b)=>{
if(a.match(b.marker)){
updated=true;
applyConditions(character,null,b.name);
}
});
});
}
if(!updated){
character ? setDefaultTokenForCharacter(character, obj) : undefined;
updateAllTokens(character);
}
}
}
}
}
}
}catch(err){
sendError(err);
}
},
pathHandler = function(obj,event,prev){
if(!sheetCompat){
return;
}
try{
var shapeMatch = obj.get('controlledby').match(/(\d+)ft\s+(.*?)#([^,]+)/),
connectedPaths,newLeft,newTop,
strokeColor=obj.get('stroke'),
pageID = obj.get('pageid'),
sendPath=[];
if(!shapeMatch){
return;
}
switch(event){
case 'destroy':
if(shapeMatch[2].trim().startsWith('line')){
connectedPaths = _.filter(findObjs({type:'path'}),(p)=>{return p.get('controlledby').match(shapeMatch[3])});
_.each(connectedPaths,(p)=>{
p.remove();
});
}
break;
case 'change':
if((shapeMatch[2].startsWith('cone') && obj.get('rotation')===prev.rotation) || (shapeMatch[2].startsWith('line') && obj.get('left')===prev.left && obj.get('top')===prev.top)){
return;
}
switch(true){
case shapeMatch[2].match(/line (?:origin|target)/)!==null:
connectedPaths = _.filter(findObjs({type:'path'}),(p)=>{return p.get('controlledby').match(shapeMatch[3])});
_.each(connectedPaths,(p)=>{
if(p.get('controlledby').match(/origin/)){
sendPath.unshift(p);
}else if(p.get('controlledby').match(/target/)){
sendPath.push(p);
}else{
p.remove();
}
});
obj.set({left:(~~((obj.get('left')*1)/70))*70 + 35,top:(~~((obj.get('top')*1)/70))*70+ 35});
mapLine(sendPath,null,shapeMatch[1]*70,shapeMatch[3],strokeColor,pageID);
break;
case shapeMatch[2].startsWith('cone'):
mapCone(obj);
break;
}
break;
}
}catch(err){
sendError(err);
}
},
RegisterEventHandlers = function() {
try{
//message handling
on('chat:message', HandleInput);
//graphic handling
on('change:graphic',(obj,prev)=>{graphicHandler(obj,'change',prev)});
on('add:graphic',(obj)=>{graphicHandler(obj,'add')});
//Campaign handling
on('change:campaign:turnorder',(obj,prev)=>{campaignHandler(obj,'change',prev)});
//attribute handling
on('change:attribute',(obj,prev)=>{attributeHandler(obj,'change',prev)});
on('add:attribute',(obj,prev)=>{attributeHandler(obj,'add',prev)});
//character handling
on('add:character',(obj,prev)=>{characterHandler(obj,'add',prev)});
on('change:character',(obj,prev)=>{characterHandler(obj,'change',prev)});
//path handling
on('destroy:path',(obj)=>{pathHandler(obj,'destroy')});
on('change:path',(obj,prev)=>{pathHandler(obj,'change',prev)});
}catch(err){
sendError(err);
}
};
return {
CheckInstall: checkInstall,
RegisterEventHandlers: RegisterEventHandlers
};
}());
on("ready",function(){
'use strict';
PFCompanion.CheckInstall();
PFCompanion.RegisterEventHandlers();
});